package com.hzlj.position.locate.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.fz.common.base.dto.PageParamDTO;
import com.fz.common.base.dto.QueryPageResultDTO;
import com.fz.common.base.exception.PubException;
import com.fz.common.dict.annotation.DictConvert;
import com.google.common.collect.Lists;
import com.hzlj.common.message.common.dto.message.MessageNotifyDTO;
import com.hzlj.position.config.common.dto.common.PositionAddExtDTO;
import com.hzlj.position.config.common.dto.common.ReportLocateDTO;
import com.hzlj.position.config.common.dto.jzJbxxDeviceBind.JzJbxxDeviceBindWithLocateTimesDTO;
import com.hzlj.position.config.common.enums.ReportType;
import com.hzlj.position.config.common.enums.WarningType;
import com.hzlj.position.config.service.JzJbxxDeviceBindService;
import com.hzlj.position.locate.common.common.PositionSimpleDTO;
import com.hzlj.position.locate.common.common.ReadUpdateDTO;
import com.hzlj.position.locate.common.dto.position.PositionQueryResultDTO;
import com.hzlj.position.locate.common.dto.reportCommon.ReportHandleDTO;
import com.hzlj.position.locate.common.dto.reportInspection.ReportInspectionExtDTO;
import com.hzlj.position.locate.common.dto.reportInspection.ReportInspectionQueryParamDTO;
import com.hzlj.position.locate.common.dto.reportInspection.ReportInspectionWithJzJbxxDTO;
import com.hzlj.position.locate.common.enums.ReportStatus;
import com.hzlj.position.locate.common.model.ReportInspection;
import com.hzlj.position.locate.dao.ReportInspectionArtificialDao;
import com.hzlj.position.locate.dao.ReportInspectionDao;
import com.hzlj.position.locate.differentiation.sysCheck.traceCheck.TraceSysCheckRouter;
import com.hzlj.position.locate.service.PositionAddTaskService;
import com.hzlj.position.locate.service.ReportInspectionCorrectService;
import com.hzlj.position.locate.service.ReportInspectionService;
import com.hzlj.sqjz.config.common.dto.common.handle.HandleCommonQueryResultDTO;
import com.hzlj.sqjz.config.common.enums.HandleStatus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 通信联络核查-核查(ReportInspection)表服务接口
 *
 * @author lifh
 * @date 2023-07-21 14:20:19
 */
@Slf4j
@Service
public class ReportInspectionServiceImpl implements ReportInspectionService {
    @Resource
    private ReportInspectionDao reportInspectionDao;
    @Resource
    private PositionAddTaskService positionAddTaskService;
    @Resource
    private JzJbxxDeviceBindService jzJbxxDeviceBindService;
    @Resource
    private ReportInspectionCorrectService reportInspectionCorrectService;
    @Resource
    private ReportInspectionArtificialDao reportInspectionArtificialDao;
    @Resource
    private TraceSysCheckRouter traceSysCheckRouter;


    @Override
    public void delete(String jzId, Date date) {
        this.reportInspectionDao.delete(jzId, DateUtil.beginOfDay(date));
    }

    @Override
    public void deleteByJgCodeWithUnSuccess(String reportType,
                                            String jgCode,
                                            Date startDay,
                                            Date endDay) {
        reportInspectionDao.deleteByJgCodeWithUnSuccess(reportType, jgCode, startDay, endDay);
    }

    /**
     * 位置上报
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reportLocate(ReportLocateDTO locate) {
        JzJbxxDeviceBindWithLocateTimesDTO bind = this.jzJbxxDeviceBindService.getJzJbxxDeviceBind4LocateTimes(locate.getJzId());
        ReportInspection report = null;
        if (ObjectUtil.isNotEmpty(locate.getId())) {
            report = reportInspectionDao.getReportInspection(locate.getId(), locate.getReportTime());
        }
        //同步到positionTask中
        PositionQueryResultDTO positionResult = this.positionAddTaskService.add(locate
                .setId(locate.getId())
                .setDeviceCode(bind.getDeviceCode())
                .setChannel(bind.getChannel())
                .setChannelType(bind.getChannelType())
                .setPositionExt(new PositionAddExtDTO().setFileIds(locate.getFileIds()))
                .setDataType(getDataType(locate.getReportType(), report == null ? null : report.getExt()))
        );
        if (report == null) {
            return;
        }
        BeanUtil.copyProperties(locate, report, CopyOptions.create().ignoreNullValue());
        report.setReportStatus(ReportStatus._SUCCESS.getStatus());
        report.setBelongDay(DateUtil.beginOfDay(locate.getReportTime()));
        report.setUpdateTime(new Date());
        report.setCrossBorder(WarningType.isCross(positionResult.getWarningType()));
        report.setHandleStatus(Boolean.TRUE.equals(report.getCrossBorder()) ?
                HandleStatus.WAIT.getStatus() : HandleStatus.NONE.getStatus());
        //检验
        this.reportLocateCheck(report);
        this.updateByInspections(Lists.newArrayList(report));
        //如果是纠偏
        ReportInspectionExtDTO ext = report.getExt();
        PositionSimpleDTO positionSimple = PositionSimpleDTO.from(positionResult)
                .setFileIds(locate.getFileIds())
                .setWarningType(positionResult.getWarningType());
        if (report.getReportType().equals(ReportType.CORRECT.getCode())) {
            reportInspectionCorrectService.report(ext.getPositionId(), ext.getPositionTime(), positionSimple);
        }
        //如果是位置确认
        if (report.getReportType().equals(ReportType.TRACK_CHECK.getCode())) {
            traceSysCheckRouter.updateReportResult(bind.getJzId(), bind.getJgCode(), positionSimple, ext);
        }
    }


    /**
     * 批量更新
     */
    public void updateByInspections(List<ReportInspection> inspections) {
        this.reportInspectionDao.updateByInspections(inspections);
        List<ReportInspection> reportInspectionArtificials = inspections.stream()
                .filter(e -> e.getReportType().equals(ReportType.ARTIFICIAL.getCode()))
                .collect(Collectors.toList());
        this.reportInspectionArtificialDao.updateByInspections(reportInspectionArtificials);
    }


    @Override
    @DictConvert
    public List<ReportInspectionWithJzJbxxDTO> listReportInspection(ReportInspectionQueryParamDTO dto) {
        return this.reportInspectionDao.listReportInspection(dto);
    }

    /**
     * 查询列表：分页
     */
    @Override
    @DictConvert
    public QueryPageResultDTO<ReportInspectionWithJzJbxxDTO> pageReportInspection(ReportInspectionQueryParamDTO dto, PageParamDTO page) {
        return this.reportInspectionDao.pageReportInspection(dto, page);
    }


    /**
     * 是否可以上报
     */
    private void reportLocateCheck(ReportInspection report) {
        Date mustReportTime = getMustReportTime(report.getSpotCheckTime(), report.getMaxDelayReportMinutes());
        if (report.getReportTime().compareTo(mustReportTime) > 0) {
            log.warn("核查上报,已经超过了上报时间要求,mustReportTime={},reportTime={},{}", mustReportTime, report.getReportTime(), report);
            throw new PubException("已经超过了上报时间要求,认为是无效上报");
        }

        if (!DateUtil.isSameDay(report.getReportTime(), report.getSpotCheckTime())) {
            log.warn("核查上报,不是当天的核验记录,认为是无效上报,mustReportTime={},reportTime={},{}", mustReportTime, report.getReportTime(), report);
            throw new PubException("不是当天的核验记录,认为是无效上报");
        }
    }

    @Override
    @Transactional
    public void handle(ReportHandleDTO dto) {
        this.reportInspectionDao.handle(dto);
    }

    @Override
    public void read(ReadUpdateDTO dto) {
        this.reportInspectionDao.read(dto);
    }

    @Override
    public HandleCommonQueryResultDTO getHandleResult(String id, Date belongDay) {
        return this.reportInspectionDao.getHandleResult(id, belongDay);
    }

    @Override
    public void updateMessageNoticeExt(String id,
                                       Date belongDay,
                                       MessageNotifyDTO notify) {
        ReportInspection reportInspection = this.reportInspectionDao.getReportInspection(id, belongDay);
        //不存在
        if (reportInspection == null) {
            log.warn("没有查询核验记录，不能修改通知结果:id={},belongDay={},ext={}",
                    id, belongDay, notify);
            return;
        }
        //修改通知结果
        ReportInspection update = new ReportInspection();
        update.setId(reportInspection.getId());
        update.setBelongDay(reportInspection.getBelongDay());
        update.setExt(reportInspection.getExt());
        update.setNotice(notify.getSuccess());
        update.setNoticeFailMsg(notify.getMsg());
        if (update.getExt() == null) {
            update.setExt(new ReportInspectionExtDTO());
        }
        update.getExt().setNotice(notify.getExt());
        this.reportInspectionDao.updateByInspections(Lists.newArrayList(update));
    }


    /**
     * 必须上报的最晚时间
     */
    private Date getMustReportTime(Date spotCheckTime, Integer maxDelayReportMinutes) {
        return DateUtil.offset(spotCheckTime, DateField.MINUTE, maxDelayReportMinutes);
    }

    /**
     * 获取数据类型
     */
    private String getDataType(String reportType, ReportInspectionExtDTO ext) {
        if (ReportType.TRACK_CHECK.getCode().equals(reportType)) {
            return traceSysCheckRouter.getType(reportType, ext);
        }
        return null;
    }
}
